#pragma once

#include "../commen/util.hpp"
#include "../commen/log.hpp"
#include "../commen/mysql.hpp"
#include "redis_model.hpp"
#include <nlohmann/json.hpp>
#include <mariadb/mysql.h>
#include <memory>
#include <mutex>
#include <chrono>
#include <sstream>
#include <iomanip>
#include <vector>
#include "question.hpp"
#include "mysql_connection.hpp"
namespace ns_oj_model
{
    using namespace ns_util;
    using namespace ns_log;
    using namespace ns_mysql;
    using namespace oj_redis;
    using json = nlohmann::json;

    class OjModel
    {
    private:
        static OjModel *instance_;
        static std::mutex mutex_;
        std::unique_ptr<MySQLConnection> mysql_conn_{nullptr};
        RedisModel *redis_cache_{nullptr};
        MYSQL *mysql_{nullptr};

        // 私有构造函数
        OjModel()
        {
            try
            {
                // 初始化 MySQL 连接
                MySQLConnection *raw_mysql = MySQLConnection::GetInstance();
                mysql_ = raw_mysql->GetConnection();
                if (!mysql_)
                {
                    throw std::runtime_error("Failed to initialize MySQL connection");
                }

                // 成功后将指针移交给 unique_ptr
                mysql_conn_.reset(raw_mysql);

                // 初始化 Redis 缓存
                redis_cache_ = RedisModel::GetInstance();
                //预加载
                std::string all_questions_json;
                GetAllQuestions(&all_questions_json);
                LogMessage(Info, "OjModel initialized successfully");
            }
            catch (const std::exception &e)
            {
                LogMessage(Error, "OjModel initialization failed: %s", e.what());
                throw;
            }
        }

        // 事务管理类
        class Transaction
        {
        private:
            MYSQL *mysql_;
            bool committed_;

        public:
            explicit Transaction(MYSQL *mysql) : mysql_(mysql), committed_(false) {}

            ~Transaction()
            {
                if (!committed_)
                {
                    mysql_rollback(mysql_);
                }
            }

            void commit()
            {
                mysql_commit(mysql_);
                committed_ = true;
            }
        };

        // 辅助方法，将字符串中的特殊字符进行转义
        std::string EscapeString(const std::string &str)
        {
            std::vector<char> buffer(str.length() * 2 + 1);
            mysql_real_escape_string(mysql_, buffer.data(), str.c_str(), str.length());
            return std::string(buffer.data());
        }

        std::string TimestampToDateTime(int64_t timestamp)
        {
            auto time_point = std::chrono::system_clock::from_time_t(timestamp);
            auto time = std::chrono::system_clock::to_time_t(time_point);
            std::tm tm = *std::localtime(&time);

            std::ostringstream oss;
            oss << std::put_time(&tm, "%Y-%m-%d %H:%M:%S");
            return oss.str();
        }

        bool ExecuteQuery(const std::string &sql, std::vector<Question> *out = nullptr)
        {
            if (mysql_query(mysql_, sql.c_str()) != 0)
            {
                LogMessage(Warning, "SQL execution failed: %s\n", sql.c_str());
                return false;
            }

            if (out != nullptr)
            {
                std::unique_ptr<MYSQL_RES, decltype(&mysql_free_result)>
                    res(mysql_store_result(mysql_), mysql_free_result);
                if (!res)
                    return false;

                MYSQL_ROW row;
                while ((row = mysql_fetch_row(res.get())))
                {
                    Question q;
                    q.number = atoi(row[0]);
                    q.title = row[1] ? row[1] : "";
                    q.star = row[2] ? row[2] : "";
                    q.desc = row[3] ? row[3] : "";
                    q.header = row[4] ? row[4] : "";
                    q.tail = row[5] ? row[5] : "";
                    q.cpu_limit = atoi(row[6]);
                    q.mem_limit = atoi(row[7]);
                    q.commit_times = atoi(row[8]);
                    out->push_back(q);
                }
            }
            return true;
        }

    public:
        static OjModel *GetInstance()
        {
            if (instance_ == nullptr)
            {
                std::lock_guard<std::mutex> lock(mutex_);
                if (instance_ == nullptr)
                {
                    instance_ = new OjModel();
                }
            }
            return instance_;
        }

        // 获取所有题目
        bool GetAllQuestions(std::string *question_list)
        {
            if (!question_list)
                return false;

            try
            {
                // 1. 尝试从缓存获取
                LogMessage(Info, "Getting all questions from cache");
                if (redis_cache_->GetAllQuestionsFromCache(question_list))
                {
                    LogMessage(Info, "Got all questions from cache");
                    return true;
                }
                LogMessage(Info, "Failed to get all questions from cache");
                // 2. 从数据库获取
                std::vector<Question> questions;
                std::string sql = "SELECT * FROM " + TABLE_QUESTIONS;

                if (!ExecuteQuery(sql, &questions))
                {
                    return false;
                }

                // 3. 构建JSON并更新缓存
                json json_array = json::array();
                for (const auto &q : questions)
                {
                    json q_json;
                    if (q.ToJson(q_json))
                    {
                        LogMessage(Info, "Caching question: %s", q_json.dump().c_str());
                        json_array.push_back(q_json);
                        redis_cache_->CacheQuestion(q);
                    }
                }

                *question_list = json_array.dump();
                redis_cache_->CacheAllQuestions(*question_list);
                return true;
            }
            catch (const std::exception &e)
            {
                LogMessage(Error, "GetAllQuestions failed: %s\n", e.what());
                return false;
            }
        }

        // 获取单个题目
        bool GetOneQuestion(const std::string &number, Question *q)
        {
            if (!q)
                return false;

            try
            {
                // 1. 尝试从缓存获取
                LogMessage(Info, "Getting one question from cache");
                if (redis_cache_->GetCachedQuestion(std::stoi(number), q))
                {
                    LogMessage(Info, "Got one question from cache");
                    return true;
                }
                LogMessage(Info, "Failed to get one question from cache");
                // 2. 从数据库获取
                std::string sql = "SELECT * FROM " + TABLE_QUESTIONS +
                                  " WHERE number = " + number;
                std::vector<Question> result;

                if (ExecuteQuery(sql, &result) && !result.empty())
                {
                    *q = result[0];
                    redis_cache_->CacheQuestion(*q);
                    return true;
                }
                return false;
            }
            catch (const std::exception &e)
            {
                LogMessage(Error, "GetOneQuestion failed: %s\n", e.what());
                return false;
            }
        }

        // 添加题目
        bool AddQuestion(const std::string &in_json)
        {
            Transaction trans(mysql_);
            try
            {
                Question q;
                json j = json::parse(in_json);
                if (!q.FromJson(j))
                {
                    return false;
                }

                std::string sql = "INSERT INTO " + TABLE_QUESTIONS +
                                  " (number, title, star, description, header, tail, cpu_limit, mem_limit, commit_times) VALUES (";

                sql += std::to_string(q.number) + ", '";
                sql += EscapeString(q.title) + "', '";
                sql += EscapeString(q.star) + "', '";
                sql += EscapeString(q.desc) + "', '";
                sql += EscapeString(q.header) + "', '";
                sql += EscapeString(q.tail) + "', ";
                sql += std::to_string(q.cpu_limit) + ", ";
                sql += std::to_string(q.mem_limit) + ", 0)";

                if (ExecuteQuery(sql))
                {
                    trans.commit();
                    redis_cache_->CacheQuestion(q);
                    redis_cache_->InvalidateAllQuestionsCache();
                    return true;
                }
                return false;
            }
            catch (const std::exception &e)
            {
                LogMessage(Error, "AddQuestion failed: %s\n", e.what());
                return false;
            }
        }

        // 删除题目
        bool DeleteQuestion(const std::string &number)
        {
            Transaction trans(mysql_);
            try
            {
                std::string sql = "DELETE FROM " + TABLE_QUESTIONS +
                                  " WHERE number = " + number;

                if (ExecuteQuery(sql))
                {
                    trans.commit();
                    redis_cache_->InvalidateQuestionCache(std::stoi(number));
                    redis_cache_->InvalidateAllQuestionsCache();
                    return true;
                }
                return false;
            }
            catch (const std::exception &e)
            {
                LogMessage(Error, "DeleteQuestion failed: %s\n", e.what());
                return false;
            }
        }

        // 添加提交记录
        bool AddSubmitRecord(int64_t uid, int number, const std::string &code,
                             const std::string &status, const std::string &reason,
                             const std::string &submit_time)
        {
            Transaction trans(mysql_);
            try
            {
                std::string datetime = TimestampToDateTime(std::stoll(submit_time));
                std::string sql = "INSERT INTO " + TABLE_SUBMIT_RECORDS +
                                  " (uid, number, code, status, reason, submit_time) VALUES (";

                sql += std::to_string(uid) + ", ";
                sql += std::to_string(number) + ", '";
                sql += EscapeString(code) + "', '";
                sql += status + "', '";
                sql += EscapeString(reason) + "', '";
                sql += datetime + "')";

                if (ExecuteQuery(sql))
                {
                    trans.commit();
                    return true;
                }
                return false;
            }
            catch (const std::exception &e)
            {
                LogMessage(Error, "AddSubmitRecord failed: %s\n", e.what());
                return false;
            }
        }

        // 获取提交记录
        bool GetSubmitRecords(int64_t uid, int number, std::vector<SubmitRecord> *records)
        {
            if (!records)
                return false;

            try
            {
                std::string sql = "SELECT id, uid, number, code, status, reason, submit_time FROM " +
                                  TABLE_SUBMIT_RECORDS + " WHERE uid = " + std::to_string(uid);

                if (number > 0)
                {
                    sql += " AND number = " + std::to_string(number);
                }
                sql += " ORDER BY submit_time DESC";

                if (mysql_query(mysql_, sql.c_str()) != 0)
                {
                    return false;
                }

                std::unique_ptr<MYSQL_RES, decltype(&mysql_free_result)>
                    res(mysql_store_result(mysql_), mysql_free_result);
                if (!res)
                    return false;

                MYSQL_ROW row;
                while ((row = mysql_fetch_row(res.get())))
                {
                    SubmitRecord record;
                    record.id = std::stoll(row[0]);
                    record.uid = std::stoll(row[1]);
                    record.number = std::stoi(row[2]);
                    record.code = row[3] ? row[3] : "";
                    record.status = row[4] ? row[4] : "";
                    record.reason = row[5] ? row[5] : "";
                    record.submit_time = row[6] ? row[6] : "";
                    records->push_back(record);
                }
                return true;
            }
            catch (const std::exception &e)
            {
                LogMessage(Error, "GetSubmitRecords failed: %s\n", e.what());
                return false;
            }
        }

        // 创建题单
        bool CreateQuestionList(int64_t uid, const std::string &title,
                                const std::string &description, bool is_public,
                                const std::string &created_at, const std::string &updated_at,
                                std::string *out_json)
        {
            Transaction trans(mysql_);
            try
            {
                std::string sql = "INSERT INTO " + TABLE_QUESTION_LIST_INFO +
                                  " (uid, title, description, is_public, created_at, updated_at) VALUES (";

                sql += std::to_string(uid) + ", '";
                sql += EscapeString(title) + "', '";
                sql += EscapeString(description) + "', ";
                sql += std::to_string(is_public) + ", '";
                sql += created_at + "', '";
                sql += updated_at + "')";

                if (!ExecuteQuery(sql))
                {
                    return false;
                }

                int64_t list_id = mysql_insert_id(mysql_);
                trans.commit();

                QuestionList list;
                list.list_id = list_id;
                list.uid = uid;
                list.title = title;
                list.description = description;
                list.is_public = is_public;
                list.created_at = created_at;
                list.updated_at = updated_at;

                json j;
                if (list.ToJson(j))
                {
                    *out_json = j.dump();
                    return true;
                }
                return false;
            }
            catch (const std::exception &e)
            {
                LogMessage(Error, "CreateQuestionList failed: %s\n", e.what());
                return false;
            }
        }

        // 添加题目到题单
        bool AddToQuestionList(int64_t uid, int64_t list_id, int number,
                               const std::string &updated_at)
        {
            Transaction trans(mysql_);
            try
            {
                // 验证用户权限
                std::string check_sql = "SELECT uid FROM " + TABLE_QUESTION_LIST_INFO +
                                        " WHERE list_id = " + std::to_string(list_id);

                if (mysql_query(mysql_, check_sql.c_str()) != 0)
                {
                    return false;
                }

                std::unique_ptr<MYSQL_RES, decltype(&mysql_free_result)>
                    res(mysql_store_result(mysql_), mysql_free_result);
                if (!res)
                    return false;

                MYSQL_ROW row = mysql_fetch_row(res.get());
                if (!row || std::stoll(row[0]) != uid)
                {
                    return false;
                }

                // 添加题目
                std::string sql = "INSERT INTO " + TABLE_QUESTION_LISTS +
                                  " (list_id, number) VALUES (" +
                                  std::to_string(list_id) + ", " +
                                  std::to_string(number) + ")";

                if (!ExecuteQuery(sql))
                {
                    return false;
                }

                // 更新时间
                sql = "UPDATE " + TABLE_QUESTION_LIST_INFO +
                      " SET updated_at = '" + updated_at + "'" +
                      " WHERE list_id = " + std::to_string(list_id);

                if (!ExecuteQuery(sql))
                {
                    return false;
                }

                trans.commit();
                return true;
            }
            catch (const std::exception &e)
            {
                LogMessage(Error, "AddToQuestionList failed: %s\n", e.what());
                return false;
            }
        }

        // 获取题单列表
        bool GetQuestionList(int64_t uid, std::string *out_json)
        {
            try
            {
                std::string sql = "SELECT l.list_id, l.uid, l.title, l.description, "
                                  "l.is_public, l.created_at, l.updated_at, q.number "
                                  "FROM " +
                                  TABLE_QUESTION_LIST_INFO + " l "
                                                             "LEFT JOIN " +
                                  TABLE_QUESTION_LISTS + " q ON l.list_id = q.list_id "
                                                         "WHERE l.uid = " +
                                  std::to_string(uid) + " OR l.is_public = 1";

                if (mysql_query(mysql_, sql.c_str()) != 0)
                {
                    return false;
                }

                std::unique_ptr<MYSQL_RES, decltype(&mysql_free_result)>
                    res(mysql_store_result(mysql_), mysql_free_result);
                if (!res)
                    return false;

                std::map<int64_t, QuestionList> lists;
                MYSQL_ROW row;
                while ((row = mysql_fetch_row(res.get())))
                {
                    int64_t list_id = std::stoll(row[0]);
                    if (lists.find(list_id) == lists.end())
                    {
                        QuestionList list;
                        list.list_id = list_id;
                        list.uid = std::stoll(row[1]);
                        list.title = row[2] ? row[2] : "";
                        list.description = row[3] ? row[3] : "";
                        list.is_public = (row[4] && std::string(row[4]) == "1");
                        list.created_at = row[5] ? row[5] : "";
                        list.updated_at = row[6] ? row[6] : "";
                        lists[list_id] = list;
                    }

                    if (row[7])
                    { // 如果有题目
                        Question q;
                        if (GetOneQuestion(row[7], &q))
                        {
                            lists[list_id].questions.push_back(q);
                        }
                    }
                }

                json json_array = json::array();
                for (const auto &[_, list] : lists)
                {
                    json list_json;
                    if (list.ToJson(list_json))
                    {
                        json_array.push_back(list_json);
                    }
                }
                *out_json = json_array.dump();
                return true;
            }
            catch (const std::exception &e)
            {
                LogMessage(Error, "GetQuestionList failed: %s\n", e.what());
                return false;
            }
        }

        // 从题单中移除题目
        bool RemoveFromQuestionList(int64_t uid, int64_t list_id, int number)
        {
            Transaction trans(mysql_);
            try
            {
                // 验证用户权限
                std::string check_sql = "SELECT uid FROM " + TABLE_QUESTION_LIST_INFO +
                                        " WHERE list_id = " + std::to_string(list_id);

                if (mysql_query(mysql_, check_sql.c_str()) != 0)
                {
                    return false;
                }

                std::unique_ptr<MYSQL_RES, decltype(&mysql_free_result)>
                    res(mysql_store_result(mysql_), mysql_free_result);
                if (!res)
                    return false;

                MYSQL_ROW row = mysql_fetch_row(res.get());
                if (!row || std::stoll(row[0]) != uid)
                {
                    return false;
                }

                std::string sql = "DELETE FROM " + TABLE_QUESTION_LISTS +
                                  " WHERE list_id = " + std::to_string(list_id) +
                                  " AND number = " + std::to_string(number);

                if (!ExecuteQuery(sql))
                {
                    return false;
                }

                trans.commit();
                return true;
            }
            catch (const std::exception &e)
            {
                LogMessage(Error, "RemoveFromQuestionList failed: %s\n", e.what());
                return false;
            }
        }

        // 禁止拷贝
        OjModel(const OjModel &) = delete;
        OjModel &operator=(const OjModel &) = delete;

        // 允许移动
        OjModel(OjModel &&) = default;
        OjModel &operator=(OjModel &&) = default;
    };

    // 静态成员初始化
    OjModel *OjModel::instance_ = nullptr;
    std::mutex OjModel::mutex_;
}